﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections.ObjectModel;

namespace PowerPatcher
{
    public class Helper
    {
        private static fileHelper _fh = null;
        private static fileHelper fh
        {
            get
            {
                if (_fh == null)
                    _fh = new fileHelper();
                return _fh;
            }
        }

        /// <summary>
        /// Automatically returns the appropriate error report, based on users preferences
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        public static string ResolveExcpt(Exception ex)
        {
            return ((PowerPatcher.Properties.Settings.Default.ShowDetailedErrors) ? ex.ToString() : ex.Message);
        }

        /// <summary>
        /// Writes a string to 'PowerPatcher.log' in the current directory. If the string does not end with "\r\n", "\r\n" is appended to the string. Date/time is added automatically.
        /// </summary>
        /// <param name="text">The text to write, optionally terminated with a CrLf</param>
        public static void WriteLogLine(string text)
        {
            lock(fh)
            {
                fh.WriteLogLine(text); //This allows us to safely keep the file open, speeding up logging
            }
        }

        /// <summary>
        /// Partition a list of elements into a smaller group of elements
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="totalPartitions"></param>
        /// <returns></returns>
        public static Collection<T>[] Partition<T>(Collection<T> list, int totalPartitions)
        {
            if (list == null)
                return null;

            if (totalPartitions < 1)
                throw new ArgumentOutOfRangeException("totalPartitions");

            Collection<T>[] partitions = new Collection<T>[totalPartitions];

            int maxSize = (int)Math.Ceiling(list.Count / (double)totalPartitions);
            int k = 0;

            for (int i = 0; i < partitions.Length; i++)
            {
                partitions[i] = new Collection<T>();
                for (int j = k; j < k + maxSize; j++)
                {
                    if (j >= list.Count)
                        break;
                    partitions[i].Add(list[j]);
                }
                k += maxSize;
            }

            return partitions;
        }
        /// <summary>
        /// Returns a list of DLLs in any subdirectory of the given path
        /// </summary>
        /// <param name="dir">The starting directory</param>
        /// <param name="DirOnly">If false, does not include DLLs found in the folder specified by dir. It still returns DLLs in subdirectories</param>
        /// <returns></returns>
        public static List<string> GetDLLFiles(string dir, bool DirOnly)
        {
            List<string> Files = new List<string>();
            if (!DirOnly)
            {
                Files.AddRange(Directory.GetFiles(dir, "*.dll"));
            }
            string[] Dirs = Directory.GetDirectories(dir);
            foreach (string d in Dirs)
                Files.AddRange(GetDLLFiles(Path.Combine(dir, d), false));
            return Files;
        }
        private class fileHelper : IDisposable
        {
            StreamWriter w;
            bool disposed;

            public fileHelper()
            {
                disposed = false;
                w = new StreamWriter("PowerPatcher.log");
                w.AutoFlush = true;
            }

            public void Dispose()
            {
                if (!disposed)
                {
                    lock (w)
                    {
                        w.Close();
                        w.Dispose();
                        w = null;
                    }
                }
            }

            ~fileHelper()
            {
                Dispose();
            }

            /// <summary>
            /// Writes a string to 'PowerPatcher.log' in the current directory. If the string does not end with "\r\n", "\r\n" is appended to the string. Date/time is added automatically.
            /// </summary>
            /// <param name="text">The text to write, optionally terminated with a CrLf</param>
            public void WriteLogLine(string text)
            {
                lock (w)
                {
    #if DEBUG
                    System.Diagnostics.Debug.WriteLine(text);
    #endif
                    if (!text.EndsWith("\r\n"))
                        text += "\r\n";
                    w.Write(string.Format("{0}\t{1}", DateTime.Now, text));
                }
            }
        }
    }


    public static class AssemblyResolver
    {
        public static void AddRecord(string name, string path)
        {
            Table.Add(name, path);
        }
        private static Dictionary<string, string> Table = new Dictionary<string, string>()
        {
            {"PowerPatcherInterop", @"Extentions\Interop\PowerPatcherInterop.dll"}
        };
        public static void Register()
        {
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
        }

        static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            Dictionary<string, string> Tokens = Tokenize(args.Name, ", ");
            string Name = Tokens["Name"];
            if (Table.Keys.Contains(Name))
                return System.Reflection.Assembly.LoadFrom(Table[Name]);
            string maybeAssemPath = @"Localization\Langs\" + Tokens["Culture"] + "\\" + Tokens["Name"];
            if (File.Exists(maybeAssemPath))
                return System.Reflection.Assembly.LoadFrom(maybeAssemPath);
            return null;

        }

        public static Dictionary<string, string> Tokenize(string c, params string[] t)
        {
            string[] w, p;
            Dictionary<string, string> d = new Dictionary<string, string>();
            w = c.Split(t, StringSplitOptions.RemoveEmptyEntries);
            foreach (string s in w)
            {
                p = s.Split('=');
                if (p.Length == 1)
                {
                    d.Add("Name", p[0]);
                }
                else
                    d.Add(p[0], p[1]);
            }
            return d;
        }

    }
}
